﻿using Behaving;
using Behaving.Actions;
using Behaving.Composites;
using NUnit.Framework;

namespace Behaving.Tests.CompositeTests
{
    [TestFixture]
    public class SelectorTests
    {
        protected ExecutionCounter InEarlyBranch { get; set; }
        protected ExecutionCounter InLateBranch { get; set; }

        [Test]
        public void When_running_skips_from_earlier_branch_to_later()
        {
            BehaviourTree behaviourTree = CreateBehaviourTree();
            
            // First tick, early branch runs
            InEarlyBranch.RunningState = RunningState.Running;
            behaviourTree.Tick();
            Assertions.AssertWasStartedAndExecuted(InEarlyBranch);
            Assertions.AssertWasNotCalled(InLateBranch);

            // Second tick, early branch is finished and later branch is given a go
            InEarlyBranch.RunningState = RunningState.Failure;
            InLateBranch.RunningState = RunningState.Running;
            behaviourTree.Tick();
            Assertions.AssertWasExecutedAndStopped(InEarlyBranch);
            Assertions.AssertWasStartedAndExecuted(InLateBranch);
        }

        [Test]
        public void When_running_skips_from_later_branch_to_earlier()
        {
            BehaviourTree behaviourTree = CreateBehaviourTree();

            // First tick, late branch runs (but early branch was allready executed)
            InEarlyBranch.RunningState = RunningState.Failure;
            InLateBranch.RunningState = RunningState.Running;
            behaviourTree.Tick();
            Assertions.AssertWasStartedAndExecuted(InLateBranch);
            Assertions.AssertWasStartedExecutedAndStopped(InEarlyBranch);

            // Second tick, early branch is finished but early branch is never visited because it comes before the late branch
            InLateBranch.RunningState = RunningState.Failure;
            behaviourTree.Tick();
            Assertions.AssertWasExecutedAndStopped(InLateBranch);
            Assertions.AssertWasNotCalled(InEarlyBranch);

            // Third tick, they're both run
            InEarlyBranch.RunningState = RunningState.Failure;
            InLateBranch.RunningState = RunningState.Failure;
            behaviourTree.Tick();
            Assertions.AssertWasStartedExecutedAndStopped(InLateBranch);
            Assertions.AssertWasStartedExecutedAndStopped(InEarlyBranch);
        }

        protected BehaviourTree CreateBehaviourTree()
        {
            return
                new BehaviourTree(
                    new Selector(
                        InEarlyBranch = new ExecutionCounter(RunningState.Success).SetName("Early Branch"),
                        new FailAction(),
                        new FailAction(),
                        InLateBranch = new ExecutionCounter(RunningState.Success).SetName("Late Branch")));
        }
    }  
}